#include "Map.h"

bool Map::LoadLevel (const char* pLevel)
{
	FILE* pFile = nullptr;
	fopen_s (&pFile, pLevel, "r");

	if (pFile == nullptr)
	{
		return false;
	}
	
	fscanf_s (pFile, "%*s %d", &mTileSize);					//%* -> read but then discard
	fscanf_s (pFile, "%*s %d", &mColumns);
	fscanf_s (pFile, "%*s %d", &mRows);

	mpTiles = new int [(mColumns * mRows)];

	fgetc (pFile);

	for (int y = 0; y < mRows; ++y)
	{
		for (int x = 0; x < mColumns; ++x)
		{
			const int index = GetIndex (x, y);

			mpTiles [index] = (fgetc (pFile) - '0');
		}
		
		fgetc (pFile);
	}

	fclose (pFile);

	return true;
}
bool Map::LoadTexturePack (const char* pTexturePack)
{
	FILE* pFile = nullptr;
	fopen_s (&pFile, pTexturePack, "r");

	if (pFile == nullptr)
	{
		return false;
	}
	
	fscanf_s (pFile, "%*s %d", &mNumSprites);			//%* -> read but then discard
	mpSprites = new SGE_Sprite [mNumSprites];

	char buffer [256];

	for (int i = 0; i < mNumSprites; ++i)
	{
		fscanf_s (pFile, "%s", buffer, 256);
		mpSprites [i].Load (buffer);
	}

	fclose (pFile);

	return true;
}
bool Map::IsBlocked (int x, int y) const
{
	const int index = GetIndex (x, y);
	int type = mpTiles [index];

	return (type > 1);									//currently assumes > 1 is blocked
}
int Map::GetIndex (int x, int y) const
{
	return (x + (y * mColumns));						//(+ (z * rows * columns)) -> for 3D array
}

SRect Map::GetBoundingBox (int x, int y) const
{
	SRect boundingBox;
	boundingBox.min.x = (float)(x * mTileSize);
	boundingBox.min.y = (float)(y * mTileSize);
	boundingBox.max.x = (float)(((x + 1) * mTileSize) - 1);
	boundingBox.max.y = (float)(((y + 1) * mTileSize) - 1);

	return boundingBox;
}

Map::Map () : mpTiles (nullptr), mColumns (0), mNumSprites (0), mRows (0)
			, mTileSize (0), mpSprites (nullptr)
{}
Map::~Map ()
{

}

void Map::Load (const char* pLevel, const char* pTexturePack)
{
	Unload ();

	if (!LoadLevel (pLevel))
	{
		Unload ();
		return;
	}
	if (!LoadTexturePack (pTexturePack))
	{
		Unload ();
		return;
	}
}
void Map::Render (const SVector2& screenOffset)
{
	for (int y = 0; y < mRows; ++y)
	{
		for (int x = 0; x < mColumns; ++x)
		{
			const int index = GetIndex (x, y);
			SVector2 pos (((float)x * mTileSize), ((float)y * mTileSize));
			SVector2 renderPosition = (pos - screenOffset);

			mpSprites [mpTiles [index]].SetPosition (renderPosition);
			mpSprites [mpTiles [index]].Render ();
		}
	}
}
void Map::Unload ()
{
	for (int i = 0; i < mNumSprites; ++i)
	{
		mpSprites [i].Unload ();
	}

	delete [] mpSprites;
	mpSprites = nullptr;
	delete [] mpTiles;
	mpTiles = nullptr;

	mColumns = 0;
	mNumSprites = 0;
	mRows = 0;
	mTileSize = 0;
}
void Map::Update (float deltaTime)
{

}

bool Map::TestCollision (const SLineSegment& segment, SRect& rect) const
{
	if (segment.from.x < 0.0f || segment.from.x >= GetWidth  () ||
		segment.from.y < 0.0f || segment.from.y >= GetHeight () ||
		segment.to.x   < 0.0f || segment.to.x   >= GetWidth  () ||
		segment.to.y   < 0.0f || segment.to.y   >= GetHeight ()	  )
	{
		return false;
	}

	const int minX = (int)(segment.from.x / mTileSize);
	const int minY = (int)(segment.from.y / mTileSize);
	const int maxX = (int)(segment.to.x   / mTileSize);
	const int maxY = (int)(segment.to.y   / mTileSize);

	rect = SRect ();

	bool collision = false;
	for (int y = minY; y <= maxY; ++y)
	{
		for (int x = minX; x <= maxX; ++x)
		{
			if (IsBlocked (x, y))
			{
				rect += GetBoundingBox (x, y);
				collision = true;
			}
		}
	}

	return collision;
}